<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>LLM Embedding Sample App</title>
    <link rel="icon" href="/static/avatar.png">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">

    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>

    <style>
        .chat {
            margin: 15px 0px;
            padding: 15px;
            border-radius: 10px;
        }

        .chat-intro {
            background-color: #f4f4f4;
            color: #333;
        }

        .chat-intro>div {
            padding-left: 80px;
        }

        .chat-avatar {
            float: left;
            width: 60px;
            height: 60px;
            border-radius: 30px;
        }

        .chat-bot {
            margin-right: 60px;
            background-color: #f4f4f4;
            color: #333;
        }

        .chat-user {
            margin-left: 60px;
            background-color: #4c83f3;
            color: #fff;
        }

        .chat-thinking {
            display: none;
            width: 90px;
            background-color: #f4f4f4;
            color: #666;
        }
    </style>

    <script>
        const CHATS = '__chats__';
        const MAX_HISTORY = 100;

        function loadChats() {
            let str = localStorage.getItem(CHATS);
            if (str) {
                try {
                    return JSON.parse(str);
                } catch (err) {
                    console.error('Failed parse chats: ' + str);
                }
            }
            return [];
        }

        function storeChats(chats) {
            localStorage.setItem(CHATS, JSON.stringify(chats.slice(-MAX_HISTORY)));
        }

        function appendChatHistory(message) {
            window.__chats__.push(message);
            storeChats(window.__chats__);
        }

        function appendChatDOM(message, error) {
            let $chats = $('#chats');
            let css = 'chat-user';
            if (message.role === 'assistant') {
                css = 'chat-bot';
            }
            $chats.append(`<div class="chat ${css}"></div>`);
            let $chat = $chats.find('div.chat:last-child');
            if (error) {
                $chat.html('<span class="text-danger"></span>');
                $chat.find('span').text(message.content);
            } else {
                $chat.html(markdownit().render(message.content));
            }
        }

        async function completion(content) {
            let resp = await fetch('/ask', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    content: content
                })
            });
            return resp.json();
        }

        function ask() {
            let
                $send = $('#btn-send'),
                $reset = $('#btn-reset'),
                $input = $('#input-msg'),
                $thinking = $('#chat-thinking'),
                content = $input.val().trim();
            if (!content) {
                console.warn('Cannot ask: missing input.');
                return;
            }
            let userMessage = {
                role: 'user',
                content: content
            };
            appendChatDOM(userMessage);
            $send.attr('disabled', 'disabled');
            $reset.attr('disabled', 'disabled');
            $input.val('');
            $thinking.show();
            let errorHandler = (err) => {
                console.error(err);
                appendChatDOM({
                    role: 'assistant',
                    content: err.message || 'An error occured'
                }, true);
            };
            completion(content).then(responseData => {
                if (responseData.error) {
                    errorHandler(responseData.error);
                } else {
                    let assistantMessage = responseData.message;
                    appendChatDOM(assistantMessage);
                    appendChatHistory(userMessage);
                    appendChatHistory(assistantMessage);
                }
            }).catch(errorHandler).finally(() => {
                $thinking.hide();
                $send.removeAttr('disabled');
                $reset.removeAttr('disabled');
            });
        }

        $(function () {
            console.log('try load chats...');
            window.__chats__ = loadChats();
            console.log(`loaded ${window.__chats__.length} chats.`);
            for (let chat of window.__chats__) {
                appendChatDOM(chat);
            }
            $('#btn-send').click(ask);
            $('#btn-reset').click(() => {
                window.__chats__ = [];
                storeChats(window.__chats__);
                $('#chats').html('');
            });
        });
    </script>
</head>

<body>
    <div class="container mt-4 mb-4">
        <div class="row">
            <div class="col-12">
                <div class="nft-card">
                    <div class="chat chat-intro">
                        <img class="chat-avatar" src="/static/avatar.png">
                        <div>
                            <h3>保险经纪人</h3>
                            <div>你好，我是一位专业的保险经纪人，我可以为您解答任何关于保险的相关问题。</div>
                        </div>
                    </div>
                </div>
                <div id="chats">
                </div>
                <div id="chat-thinking" class="chat chat-thinking">
                    <div class="spinner-grow spinner-grow-sm">
                    </div>
                    <div class="spinner-grow spinner-grow-sm">
                    </div>
                    <div class="spinner-grow spinner-grow-sm">
                    </div>
                </div>

                <div class="chat-input">
                    <form class="row g-3" onsubmit="return false">
                        <div class="col-12">
                            <input id="input-msg" type="text" class="form-control" placeholder="Type message here.">
                        </div>
                        <div class="col-12">
                            <button id="btn-send" type="button" class="btn btn-primary">Send</button>
                            <button id="btn-reset" type="button" class="btn btn-danger">Reset</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
</body>

</html>